using System;
using Pine.SourceParser.Tree;
using System.Reflection.Emit;
using Pine.Core;

namespace Pine.CodeGen
{
	public static class PostfixExpressionCodeGenerator
	{		
		public static void GenerateBytecode(Context ctx, Expression expr, LocalBuilder lb) {
			PostfixExpression pf = (PostfixExpression) expr;
			if (pf.baseExpr is NameIdentifier) {
				LocalBuilder baseExprResult = ctx.il.DeclareLocal(typeof(Value));
				pf.baseExpr.GenerateBytecode(ctx, baseExprResult);
				ctx.il.Emit(OpCodes.Ldloc, baseExprResult);
				ctx.il.Emit(OpCodes.Stloc, lb);
				
				ctx.il.Emit(OpCodes.Ldloc, baseExprResult);
				ctx.il.Emit(OpCodes.Callvirt, typeof(Value).GetMethod( pf.increment ? "Increment" : "Decrement" ));
				ctx.il.Emit(OpCodes.Stloc, baseExprResult);
				CodeUtilities.MakeScopeWrite(ctx, ((NameIdentifier) pf.baseExpr).name, baseExprResult);
				return;
			} else if (pf.baseExpr is ArrayAccessExpression) {
				LocalBuilder baseExprResult = ctx.il.DeclareLocal(typeof(Value));
				pf.baseExpr.GenerateBytecode(ctx, baseExprResult);
				ctx.il.Emit(OpCodes.Ldloc, baseExprResult);
				ctx.il.Emit(OpCodes.Stloc, lb);
				
				LocalBuilder array = ctx.il.DeclareLocal(typeof(Value));
				((ArrayAccessExpression) pf.baseExpr).left.GenerateBytecode(ctx, array);
				LocalBuilder key = ctx.il.DeclareLocal(typeof(Value));
				((ArrayAccessExpression) pf.baseExpr).right.GenerateBytecode(ctx, key);
				
				ctx.il.Emit(OpCodes.Ldloc, array);
				ctx.il.Emit(OpCodes.Ldloc, key);
				ctx.il.Emit(OpCodes.Ldloc, baseExprResult);
				ctx.il.Emit(OpCodes.Callvirt, typeof(Value).GetMethod( pf.increment ? "Increment" : "Decrement" ));
				ctx.il.Emit(OpCodes.Callvirt, typeof(Value).GetMethod("SetArrayElement", new Type[] { typeof(Value), typeof(Value) }));
			} else {
				throw new Exception("Postfix expression for " + pf.baseExpr.GetType() + " invalid or not yet implemented");
			}
		}
	}
}

